package com.kitty.mina;

import com.kitty.common.utils.SpringUtils;
import com.kitty.game.gate.model.QueueUpService;
import com.kitty.game.role.model.Account;
import com.kitty.game.role.model.Role;
import com.kitty.game.utils.Const;
import com.kitty.game.utils.ProtocalSet;
import com.kitty.listener.EventDispatcher;
import com.kitty.listener.EventType;
import com.kitty.listener.event.LogoutEvent;
import com.kitty.mina.cache.DataCache;
import com.kitty.mina.cache.SessionUtils;
import com.kitty.mina.message.IMessageDispatcher;
import com.kitty.mina.message.Message;
import com.kitty.mina.session.SessionManager;
import com.kitty.mina.session.SessionProperties;
import com.kitty.mina.task.ThreadLocalUtil;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ServerSocketIoHandler extends IoHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(ServerSocketIoHandler.class);

    private static final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(16);

    /**
     * 消息分发器
     */
    private final IMessageDispatcher messageDispatcher;

    public ServerSocketIoHandler(IMessageDispatcher messageDispatcher) {
        this.messageDispatcher = messageDispatcher;
    }

    @Override
    public void sessionOpened(final IoSession session) {
//        ModuleCounterFilter.getCounter(session);
//        String clientIP = ((InetSocketAddress)session.getRemoteAddress()).getAddress().getHostAddress();
//        if (!ModuleCounterFilter.canConnect()) {
//            session.closeNow();
//            logger.error("[MODULE_COUNTER] 全局策略拒绝连接 {}", clientIP);
//            return;
//        }
//
//        if (ModuleCounterFilter.G_BAN_IP.contains(clientIP)) {
//            ModuleCounterFilter.banIp(session);
//            logger.error("[MODULE_COUNTER] BAN_IP 拒绝连接 {}", clientIP);
//            return;
//        }

//        executor.schedule(() -> {
//            if (session.isActive()) {
//                ModuleCounter moduleCounter = ModuleCounterFilter.getCounter(session);
//                if (moduleCounter.getCounterMap().size() == 0) {
//                    session.closeNow();
//                    logger.error("[MODULE_COUNTER] 连接idle {}ms 检测踢出:{}", ModuleCounterFilter.G_IDLE_TIME, clientIP);
//                }
//
//            }
//        }, ModuleCounterFilter.G_IDLE_TIME, TimeUnit.MILLISECONDS);
    }

    @Override
    public void sessionClosed(IoSession session) {
        /**session断开的时候删除掉排队的队列*/
        String sid = SessionManager.INSTANCE.getSessionAttr(session, SessionProperties.ACCOUNT_SID, String.class);
        SpringUtils.getBean(QueueUpService.class).remove(sid);

        /**session断开减少unchecked*/
//        ModuleCounter counter = SessionManager.INSTANCE.getSessionAttr(session, SessionProperties.MODULE_COUNTER, ModuleCounter.class);
//        if (!counter.isChecked()) {
//            int count = ModuleCounterFilter.G_UNCHECKED_PLAYER.decrementAndGet();
            //logger.error("[MODULE_COUNTER] session断开 unchecked减少至: {} 当前连接状态 {}", count, ModuleCounterFilter.canConnect());
//        }

        Role role = SessionUtils.getRoleBySession(session);
        if (role == null) {
            return;
        }
        try {
            ThreadLocalUtil.addLocalTask(role, () -> {
                onPlayerLogout(role);
            });
        } catch (Exception e) {
            logger.error("Session关闭错误信息===={}", Lang.getStackTrace(e));
        }
    }

    private void onPlayerLogout(Role role) {

        if(role != null){
            if(role.getExtendBox().getTuoguanstate()==1){
                DataCache.ONLINE_ROLES_lixian.put(role.getUid(), role);
                return;
            }
        }

        Account account = SpringUtils.getAccountService().getAccount(role.getSid());
        synchronized (account) {
            IoSession nowSession = SessionUtils.getSessionBy(role.getUid());
            if (nowSession == null || !nowSession.isActive()) {
                /**产生一个登出事件*/
                EventDispatcher.getInstance().fireEvent(new LogoutEvent(EventType.LOGOUT, role));

                /**在线列表删除掉此角色*/
                SpringUtils.getRoleService().removeOnline(role);
                /**添加到离线列表*/
                SpringUtils.getRoleService().addOffline(role);

                logger.warn("removeSession  uid:{} ", role.getUid());
                SessionManager.INSTANCE.unRegisterSession(role.getRoleId());
            }
        }
    }

    @Override
    public void sessionCreated(IoSession session) {
        session.setAttributeIfAbsent(SessionProperties.DISTRIBUTE_KEY, SessionManager.INSTANCE.getNextDistributeKey());
        SessionManager.INSTANCE.add2Anonymous(session);
    }

    @Override
    public void messageReceived(IoSession session, Object data) {
        Message message = (Message) data;
        // 如果session角色不存在，就返回，什么也不做 45144 9040
        InetSocketAddress remoteAddress = (InetSocketAddress) session.getRemoteAddress();
        if (!ProtocalSet.loginSet.contains(message.getModule())) {
            Role role = SessionUtils.getRoleBySession(session);
            if (role == null) {
                // 发个协议让用户退出登录
                logger.warn("角色不存在，退出登录,session={} Module={} ip={} message={}",
                        session.getId(), message.getModule(), remoteAddress.getAddress().getHostAddress(), Json.toJson(message));
//                ModuleCounterFilter.banIp(session);
                session.closeNow();
                return;
            }
        }

        HashMap<String, Long> heartbeatMap = SessionManager.INSTANCE.getSessionAttr(session, SessionProperties.HEARTBEAT_MAP, HashMap.class);
        long lastHeartTime = heartbeatMap.getOrDefault(Const.LAST_HEART_TIME, 0L);/**上一次的心跳时间*/
        long currReqTime = heartbeatMap.getOrDefault(Const.REQ_CURR_TIME, 0L);/**当前封包的请求时间*/
        /**如果上次的心跳时间大于0*/
        if (lastHeartTime > 0) {
            /**如果当前封包时间-上次心跳的时间 小于0  或者大于 15000 说明封包不是最新的*/
            long check =currReqTime - lastHeartTime;
            if (check < 0 || check > 15000) {
                logger.warn("请求包异常，moduleId:{}, 上次心跳时间:{}，当前请求时间:{}", message.getModule(), lastHeartTime, currReqTime);
                return;
            }
        }
        messageDispatcher.dispatch(session, message);
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) {
        if (cause instanceof IOException) {
            session.closeNow();
        } else {
            Role role = SessionUtils.getRoleBySession(session);
            if (role != null) {
                logger.error("exceptionCaught userId={} username-{}", role.getRoleId(), role.getName());
            }
            logger.error("exceptionCaught sessionId={} exception-{}", session.getId(), Lang.getStackTrace(cause));
        }
    }
}
